package geppetto.cat.alignments;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
/**
 * 
 * 
 * @author wlin
 * 
 */
abstract public class AbstractAlignmentsCache {
	protected AlignmentsSet alignmentsSet;
	protected int conflitSentenceNumber = -1;
	protected List<Integer>[] sources;
	protected List<Integer>[] foreigns;
	
	protected ArrayList<Integer[]>[][] positionsToMinimalPhrase;
	protected int minimalPhraseSentenceNumber = -1;	

	public AbstractAlignmentsCache(AlignmentsSet alignmentsSet) {
		super();
		this.alignmentsSet = alignmentsSet;
	}

	public boolean hasConflits(int sentence, int sourceIndexStart, int sourceIndexEnd,
			int foreignIndexStart, int foreignIndexEnd) {
		if (conflitSentenceNumber != sentence) {
			initNewConflitCache(sentence);
		}
//		System.out.println("looking for " + sourceIndexStart + " to " + sourceIndexEnd);

		for (int f = foreignIndexStart; f <= foreignIndexEnd; f++){
			for(int s : sources[f]){
				if(s < sourceIndexStart || s > sourceIndexEnd){
					return true;
				}
			}
		}
		for (int s = sourceIndexStart; s <= sourceIndexEnd; s++){
			for(int f : foreigns[s]){
				if(f < foreignIndexStart || f > foreignIndexEnd){
					return true;
				}
			}
		}
		
		return false;
	}

	private void initNewConflitCache(int sentence) {
		conflitSentenceNumber = sentence;
		Alignment alignment = alignmentsSet.get(sentence);
		sources = new List[alignment.getForeignLenght()];
		foreigns = new List[alignment.getSourceLenght()];
		for (int s = 0; s < alignment.getForeignLenght(); s++) {
			sources[s] = new LinkedList<Integer>();
		}
		for (int f = 0; f < alignment.getSourceLenght(); f++) {
			foreigns[f] = new LinkedList<Integer>();
		}
		for (int s = 0; s < alignment.getSourceLenght(); s++) {
			for (int f = 0; f < alignment.getForeignLenght(); f++) {
				if (hasPosition(alignment, s, f)) {
					sources[f].add(s);
					foreigns[s].add(f);
				}
			}
		}
	}
	
	public ArrayList<Integer[]> getPhrasesWithPoint(int sentence, int s, int t){
		if(minimalPhraseSentenceNumber != sentence){
			Alignment al = alignmentsSet.get(sentence);
			positionsToMinimalPhrase = new ArrayList[al.getSourceLenght()][al.getForeignLenght()];
			for(int i = 0; i < al.getSourceLenght(); i++){
				for(int j = 0; j < al.getForeignLenght(); j++){
					positionsToMinimalPhrase[i][j] = new ArrayList<Integer[]>();
				}
			}
			for (int sourceStart = 0; sourceStart < al.getSourceLenght(); sourceStart++) {
				for(int sourceEnd = 0; sourceEnd < al.getSourceLenght(); sourceEnd++){
					for(int targetStart = 0; targetStart < al.getForeignLenght(); targetStart++){
						for(int targetEnd = 0; targetEnd < al.getForeignLenght(); targetEnd++){
							if(isPhrase(sentence, sourceStart, sourceEnd, targetStart, targetEnd)){
								int size = (sourceEnd - sourceStart + 1)*(targetEnd - targetStart + 1);
								Integer[] phrase = new Integer[]{size,sourceStart,sourceEnd,targetStart,targetEnd};
								for(int i = sourceStart; i <= sourceEnd; i++){
									for(int j = targetStart; j <= targetEnd; j++){
										positionsToMinimalPhrase[i][j].add(phrase);										
									}
								}
							}
						}
						
					}
				}
			}
			minimalPhraseSentenceNumber = sentence;
		}
		return positionsToMinimalPhrase[s][t];
	}
	
	public boolean isPhrase(int sentence, int sourceStart, int sourceEnd, int targetStart, int targetEnd){
		Alignment al = alignmentsSet.get(sentence);
		boolean hasSurePositions = false;
		for (int fpos = targetStart; !hasSurePositions && fpos <= targetEnd; fpos++) {
			for (int spos = sourceStart; !hasSurePositions && spos <= sourceEnd; spos++) {
				if (hasPosition(al, spos, fpos)) {
					hasSurePositions = true;
				}
			}
		}
		// check if there is at least one aligned point
		if(hasSurePositions && !hasConflits(sentence, sourceStart, sourceEnd, targetStart, targetEnd)){
//			System.out.println("accepted");
			return true;
		}
		return false;
	}
	
	abstract public boolean hasPosition(Alignment al, int indexSrc, int indexTar);
}